package top.zt9.listener;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qf.constant.CacheConstants;
import com.qf.constant.RabbitMQConstants;
import com.qf.constant.StrategyConstants;
import com.qf.model.StandardReport;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import top.zt9.api.CacheFeign;
import top.zt9.config.DelayedConfig;

import java.io.IOException;
import java.util.Map;

/**
 * 推送是否成功的消息给客户端
 *
 * @Author ztf
 * @Date 17:03 2021/11/25
 **/
@Component
@Slf4j
public class PushReportListener {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private CacheFeign cacheFeign;

    @Autowired
    private ObjectMapper objectMapper;

    //延时发送的时间
    private final String[] TTL = {"0", "5000", "30000", "600000", "600000"};

    /**
     * 监听推送消息队列
     *
     * @param message
     * @param channel
     * @param report
     */
    @RabbitListener(queues = RabbitMQConstants.TOPIC_PUSH_SMS_REPORT)
    public void messageHandler(Message message, Channel channel, StandardReport report) throws IOException {
        //1. 接收report对象，判断clientid到redis中获取client对象
        Map<String, String> client = cacheFeign.hMGet(CacheConstants.CACHE_PREFIX_CLIENT + report.getClientID());

        //创建限流策略的key

        if (client == null) {
            log.info("【接口模块 - 推送监听器】 获取client为空");
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            return;
        }
        //2. 根据client对象获取回调地址,获取客户是否需要推送状态
        String receivestatusurl = client.get("receivestatusurl");
        String isreturnstatus = client.get("isreturnstatus");
        //3. 判断用户是否需要推送
        if ("0".equals(isreturnstatus)) {
            //客户不需要推送
            log.info("【接口模块 - 推送监听器】客户不需要推送，执行完成！report={}", report);


            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            return;
        }
        //4. 如果用户需要推送，那么封装http请求，将report推送给服务器地址
        String result = sendReport(report, receivestatusurl);

        if ("SUCCESS".equalsIgnoreCase(result)) {
            //5. 判断返回的状态码，如果是success发送完成

            log.info("【接口模块 - 推送监听器】推送成功，短信发送完成");
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);

            return;
        } else {
            //6. 如果返回的状态码为null，那么将消息发送至延时队列，发送次数+1
            report.setSendCount(report.getSendCount() + 1);
            sendReportToDelayedQueue(report);

            log.info(("【接口模块 - 推送监听器】推送失败，将消息发送至延时队列 report={}"), report);
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            return;

        }


    }

    /**
     * 监听延时队列
     * 获取需要再次发送的Report对象，发送到指定的客户方url地址
     *
     * @param message
     * @param channel
     * @param report
     */
    @RabbitListener(queues = DelayedConfig.DELAYED_QUEUE)
    public void delayedRabbitHandler(Message message, Channel channel, StandardReport report) throws IOException {
        //1. 发送次数计数
        report.setSendCount(report.getSendCount() + 1);
        //2. 发送
        Map<String, String> client = cacheFeign.hMGet(CacheConstants.CACHE_PREFIX_CLIENT + report.getClientID());
        if (client == null) {
            log.info("【接口模块 - 推送监听器】 获取client为空");
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            return;
        }
        String receivestatusurl = client.get("receivestatusurl");

        String result = sendReport(report, receivestatusurl);
        //3. 接收返回的状态，如果为success，发送停止
        if ("SUCCESS".equalsIgnoreCase(result)) {
            log.info("【接口模块 - 延时队列监听器】 发送成功，report={}", report);
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            return;
        }
        //4. 如果接收的返回状态为空，那么判断发送次数，如果超过五次，停止发送，如果小于五次，再次进入延时队列
        sendReportToDelayedQueue(report);
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }


    /**
     * 发送http请求给指定的url地址
     *
     * @param report 发送内容
     * @param url    发送地址
     * @return
     */
    private String sendReport(StandardReport report, String url) throws JsonProcessingException {
        //1. 封装请求头对象
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
        //2. 封装请求体对象
        String jsonStr = objectMapper.writeValueAsString(report);
        HttpEntity<String> entity = new HttpEntity<>(jsonStr,httpHeaders);
        //3. 发送并返回接收状态
        String result = restTemplate.postForObject(url, entity, String.class);
        return result;
    }

    /**
     * 发送短信对象至延时队列
     *
     * @param report
     */
    private void sendReportToDelayedQueue(StandardReport report) {
        if (report.getSendCount() > 4) {
            log.info("【接口模块 - 延时队列监听器】 发送失败，发送次数大于5次停止发送，report={}", report);
            return;
        }
        //如果小于五次，再次进入延时队列
        rabbitTemplate.convertAndSend(DelayedConfig.DELAYED_EXCHANGE, "report", report, new MessagePostProcessor() {

            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                message.getMessageProperties().setExpiration(TTL[report.getSendCount()]);
                return message;
            }
        });

    }
}
